package com.xiaotao.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.nimbusds.jose.JOSEException;
import com.xiaotao.dto.*;
import com.xiaotao.entity.Goods;
import com.xiaotao.entity.Merchant;
import com.xiaotao.mapper.GoodsMapper;
import com.xiaotao.mapper.GroupBuyMapper;
import com.xiaotao.mapper.MerchantMapper;
import com.xiaotao.service.MerchantService;
import com.xiaotao.util.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.geo.GeoResult;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.util.UriComponentsBuilder;

import javax.annotation.Resource;
import java.net.URI;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class MerchantServiceImpl implements MerchantService {
    @Resource
    private MerchantMapper merchantMapper;
    @Resource
    private GoodsMapper goodsMapper;
    @Resource
    private GroupBuyMapper groupBuyMapper;
    @Resource
    private MinioUtil minioUtil;
    @Resource
    private RedisGeoUtil redisGeoUtil;
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private RedisTemplate redisTemplateInit;
    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    @Value("${amap.key}")
    private String key;
    @Value("${amap.regeo-url}")
    private String regeoApiUrl;

    @Value("${amap.geocode-url}")
    private String geocodeUrl;  // 高德地理编码API地址



    /**
     * 添加商户
     *
     * @param merchant
     * @return
     */
    @Override
    public ResponseUtil save(Merchant merchant) {
        int result = merchantMapper.insert(merchant);
        return result > 0 ? ResponseUtil.get(ResponseEnum.OK) :
                ResponseUtil.get(ResponseEnum.FAIL);
    }


    /**
     * 商户登录
     *
     * @param merchant
     * @return
     */
    @Override
    public ResponseUtil login(Merchant merchant) throws JOSEException {
        if (merchant.getUsername().isEmpty() || merchant.getPassword().isEmpty()) {
            return ResponseUtil.get(ResponseEnum.FAIL, "商户用户密码不能为空");
        }
        //根据用户名查询密码
        Merchant merchant1 = merchantMapper.findByUsername(merchant.getUsername());
        if (!merchant.getPassword().equals(merchant1.getPassword())) {
            //密码错误
            return ResponseUtil.get(ResponseEnum.FAIL, "密码或者用户名错误");
        }
        Map<String, Object> map = new HashMap<>();
        map.put("merchant", merchant1);
        map.put("id", merchant1.getId());
        String token = JwtUtil.getToken(map);
        //修改token,有问题前台小程序和后台用户id相同会出问题
        stringRedisTemplate.opsForValue().set("token" + merchant1.getId(), token, 3, TimeUnit.HOURS);
        return ResponseUtil.get(ResponseEnum.OK, token);
    }

    /**
     * 查询所有商户
     *
     * @return
     */
    @Override
    public ResponseUtil findAll(Integer pageNum, Integer pageSize) {
        //分页
        PageHelper.startPage(pageNum, pageSize);
        List<Merchant> list = merchantMapper.findAll();
        PageInfo<Merchant> pageInfo = new PageInfo<>(list);
        return list != null ? ResponseUtil.get(ResponseEnum.OK, pageInfo) :
                ResponseUtil.get(ResponseEnum.FAIL);
    }

    /**
     * 删除商户
     *
     * @param id
     * @return
     */
    @Transactional
    @Override
    public ResponseUtil delete(Integer id) {
        Merchant merchant = merchantMapper.selectByPrimaryKey(id);
        if (merchant == null) {
            // 避免merchant为null时调用merchant.getId()导致空指针异常
            return ResponseUtil.get(ResponseEnum.FAIL, "商户不存在");
        }

        //删除与该用户相关联的团购和商品
        List<Goods> list = goodsMapper.findByMerchantId(merchant.getId());
        if (list != null && !list.isEmpty()) {
            goodsMapper.batchDelete(list);
        }
        //根据商户信息找到所有未删除的团购信息
        List<GroupBuyDto> groupBuyList = groupBuyMapper.findByMerchantId(id);
        if (groupBuyList != null && !groupBuyList.isEmpty()) {
            groupBuyMapper.batchDelete(groupBuyList);
        }
        int result = merchantMapper.deleteByPrimaryKey(id);
        //删除缓存
        redisGeoUtil.removeMerchantLocation(id);
        return result > 0 ? ResponseUtil.get(ResponseEnum.OK, "删除成功") :
                ResponseUtil.get(ResponseEnum.FAIL, "删除失败");
    }

    /**
     * 根据id查询商户信息
     *
     * @param id
     * @return
     */
    @Override
    public ResponseUtil findById(Integer id) {
        Merchant merchant = merchantMapper.selectByPrimaryKey(id);
        return merchant != null ? ResponseUtil.get(ResponseEnum.OK, merchant) :
                ResponseUtil.get(ResponseEnum.FAIL);
    }

    @Override
    public ResponseUtil uploadImage(MultipartFile file, String bucketName) throws Exception {
        Map<String, Object> map = minioUtil.uploadFile(file, bucketName);
        String imageUrl = map.get("url").toString();
        return imageUrl != null ? ResponseUtil.get(ResponseEnum.OK, imageUrl) :
                ResponseUtil.get(ResponseEnum.FAIL, "上传文件失败");
    }

    @Override
    public ResponseUtil searchByKeyWord(String keyword, Integer status, Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<Merchant> merchantList = merchantMapper.searchByKeyWord(keyword, status);
        PageInfo<Merchant> merchantPageInfo = new PageInfo<>(merchantList);
        return merchantList != null ? ResponseUtil.get(ResponseEnum.OK, merchantPageInfo) :
                ResponseUtil.get(ResponseEnum.FAIL);
    }

    @Override
    public ResponseUtil update(Merchant merchant) {
        //更新商户信息，由于管理员分配的只有账号密码，商户名，其他信息要商家完善，完善信息时将经纬度信息存入redis
        if (merchant.getLongitude() != null && merchant.getLatitude() != null) {
            redisGeoUtil.addMerchantLocation(merchant);
        }
        int result = merchantMapper.updateByPrimaryKeySelective(merchant);
        return result > 0 ? ResponseUtil.get(ResponseEnum.OK, "更新成功") :
                ResponseUtil.get(ResponseEnum.FAIL, "更新失败");
    }

    @Override
    public ResponseUtil findAll2() {
        List<Merchant> list = merchantMapper.findAll();
        return list != null ? ResponseUtil.get(ResponseEnum.OK, list) :
                ResponseUtil.get(ResponseEnum.FAIL);
    }

    @Override
    public ResponseUtil getNearbyMerchants(Double userLon, Double userLat, Double radius, Long limit) {
        // 1. 调用 Redis GEO 查询附近商户ID和距离
        GeoResults<RedisGeoCommands.GeoLocation<Object>> geoResults =
                redisGeoUtil.searchNearbyMerchants(userLon, userLat, radius, limit);

        // 2. 转换结果并补充商户详情
        List<MerchantDto> result = new ArrayList<>();
        List<Integer> merchantIds = new ArrayList<>();
        if (geoResults != null) {
            for (GeoResult<RedisGeoCommands.GeoLocation<Object>> geoResult : geoResults) {
                MerchantDto merchantDto = new MerchantDto();
                RedisGeoCommands.GeoLocation<Object> content = geoResult.getContent();//获取详细内容信息
                Integer merchantId = (Integer) content.getName();//商户id
                merchantDto.setId(merchantId);
                merchantDto.setDistance(geoResult.getDistance());//距离单位km
                merchantIds.add(merchantId);
                result.add(merchantDto);
            }
        }
        if(merchantIds!=null&&!merchantIds.isEmpty()){
            List<Merchant> byIds = merchantMapper.findByIds(merchantIds);
            Map<Integer, Merchant> merchantMap = new HashMap<>();
            for (Merchant merchant : byIds) {
                merchantMap.put(merchant.getId(), merchant);
            }
            for (MerchantDto merchantDto : result) {
                Merchant merchant = merchantMap.get(merchantDto.getId());
                if (merchant != null) {
                    BeanUtils.copyProperties(merchant, merchantDto);
                }
            }
        }
        return result != null ? ResponseUtil.get(ResponseEnum.OK, result) :
                ResponseUtil.get(ResponseEnum.FAIL);
    }

    @Override
    public ResponseUtil getDetail(Integer merchantId) {
        Merchant merchant = merchantMapper.selectByPrimaryKey(merchantId);
        List<Goods> list = goodsMapper.findByMerchantId(merchantId);
        List<GroupBuyDto> groupBuyDtoList = groupBuyMapper.findByMerchantId(merchantId);
        MerchantDetailDto merchantDetailDto = new MerchantDetailDto(merchant, list, groupBuyDtoList);
        return merchantDetailDto != null ? ResponseUtil.get(ResponseEnum.OK, merchantDetailDto) :
                ResponseUtil.get(ResponseEnum.FAIL);
    }

    /**
     * 通过地址获取经纬度
     * @param address 详细地址（如：北京市朝阳区建国路88号）
     * @return 经纬度信息
     */
    public ResponseUtil getLocationByAddress(String address) {
// 1. 构建请求URL（带参数）
        URI uri = UriComponentsBuilder.fromHttpUrl(geocodeUrl)
                .queryParam("address", address)  // 地址参数
                .queryParam("output", "json")    // 返回格式
                .queryParam("key", key)      // 高德API密钥
                .build()
                .toUri();

        // 2. 发送GET请求，获取高德API响应（JSON字符串）
        String responseJson = restTemplate.getForObject(uri, String.class);

        // 3. 解析JSON响应
        JSONObject jsonObject = JSONObject.parseObject(responseJson);

        // 4. 处理响应结果（高德API格式：{"status":"1","count":"1","geocodes":[...]}）
        if ("1".equals(jsonObject.getString("status")) && jsonObject.getInteger("count") > 0) {
            String location = jsonObject.getJSONArray("geocodes")
                    .getJSONObject(0)
                    .getString("location"); // 格式："经度,纬度"
            String[] lonLat = location.split(",");

            Location result = new Location();
            result.setLongitude(lonLat[0]);
            result.setLatitude(lonLat[1]);
            return ResponseUtil.get(ResponseEnum.OK,result);
        } else {
            // 解析失败，抛出异常（由控制器捕获处理）
            String errorMsg = jsonObject.getString("info") != null ?
                    jsonObject.getString("info") : "地址解析失败，请检查地址是否正确";
            throw new RuntimeException(errorMsg);
        }
    }
}
